package arkham.gui;

import java.awt.Color;
import java.awt.Dimension;

import javax.swing.*;
import javax.swing.text.*;

import arkham.util.AHLogger;
import arkham.util.XmlTools;

public class ChatManager {

	private JTextPane chatbox;
	private JTextField chatField;
	private StyledDocument styledDoc;
	private String ownUsername;
	private CommandListener clistener;
	private boolean showOwnInfo, showMetaInfo;

	public ChatManager(String username)
	{
		chatbox = new JTextPane();
		styledDoc = chatbox.getStyledDocument();
		this.ownUsername = username;
		chatbox.setEditable(false);
		chatField = new JTextField(80);
		chatField.setDocument(new JTextFieldLimit(100));
		chatField.setActionCommand("chat");
		showMetaInfo = true;
		showOwnInfo = true;
		initStyles();
	}

	/**
	 * Initializes some style constants
	 */
	private void initStyles()
	{
		//Initialize some styles.
		Style def = StyleContext.getDefaultStyleContext().
		getStyle(StyleContext.DEFAULT_STYLE);

		Style regular = styledDoc.addStyle("regular", def);
		StyleConstants.setFontFamily(def, "Arial");

		Style s = styledDoc.addStyle("italic", regular);
		StyleConstants.setItalic(s, true);

		s = styledDoc.addStyle("bold", regular);
		StyleConstants.setBold(s, true);

		s = styledDoc.addStyle("small", regular);
		StyleConstants.setFontSize(s, 10);

		s = styledDoc.addStyle("large", regular);
		StyleConstants.setFontSize(s, 16);

		for (int i = 0; i < XmlTools.SUPPORTED_COLORS.length; i++)
		{
			s = styledDoc.addStyle(XmlTools.SUPPORTED_COLORS[i], regular);
			StyleConstants.setForeground(s, XmlTools.translateColorString(XmlTools.SUPPORTED_COLORS[i]));
		}

		s = styledDoc.addStyle("alert", styledDoc.getStyle("bold"));
		StyleConstants.setForeground(s, Color.red);

		s = styledDoc.addStyle("meta", styledDoc.getStyle("bold"));
		StyleConstants.setForeground(s, new Color(0, 96, 0));

		s = styledDoc.addStyle("selfInfo", styledDoc.getStyle("bold"));
		StyleConstants.setForeground(s, new Color(128, 32, 128));
	}

	/**
	 * Sets the command listener for the chat manager
	 * @param clist the command listener
	 */
	public void setCommandListener(CommandListener clist)
	{
		this.clistener = clist;
	}

	/**
	 * The client issues a / command which should not be treated as a chat message
	 * @param command the command string
	 */
	public void slashCommand(String command)
	{
		String[] tokens = command.split(" ");
		if (tokens[0].equals("help"))
		{
			displayMessage("List of commands: help, meta, info, lookup, use.");
		}
		else if (tokens[0].equals("meta"))
		{
			/* Meta command: toggle meta information starting with # */
			if (tokens.length < 2)
			{
				displayMessage("/meta [on|off]: Toggle meta-updates about other players and the game.");
				return;
			}
			else
			{
				if (tokens[1].equals("on"))
				{
					showMetaInfo = true;
					displayMessage("Meta information on.");
				}
				else if (tokens[1].equals("off"))
				{
					showMetaInfo = false;
					displayMessage("Meta information off.");
				}
				else
				{
					displayMessage("/meta [on|off]: Toggle meta-updates about other players");
					return;
				}
			}
		}
		else if (tokens[0].equals("info"))
		{
			/* Info command: toggles information starting with * */
			if (tokens.length < 2)
			{
				displayMessage("/info [on|off]: Toggle info updates about self.");
				return;
			}
			else
			{
				if (tokens[1].equals("on"))
				{
					showOwnInfo = true;
					displayMessage("Self information on.");
				}
				else if (tokens[1].equals("off"))
				{
					showOwnInfo = false;
					displayMessage("Self information off.");
				}
				else
				{
					displayMessage("/info [on|off]: Toggle info updates about self.");
					return;
				}
			}
		}
		else
		{
			if (clistener != null)
			{
				clistener.commandReceived(tokens);
				return;
			}
		}
	}

	/**
	 * Displays a message in the chat box
	 * @param msg The message to display
	 */
	public void displayMessage(String msg)
	{
		if (!showOwnInfo && msg.startsWith("*"))
		{
			return;
		}
		if (!showMetaInfo && msg.startsWith("#"))
		{
			return;
		}
		try
		{
			// impose a 5000 character limit
			while (styledDoc.getLength() > 5000)
			{
				int firstNewline = styledDoc.getText(0, styledDoc.getLength()).indexOf('\n');
				styledDoc.remove(0, firstNewline);
			}
			if (styledDoc.getLength() > 0)
			{
				styledDoc.insertString(styledDoc.getLength(), "\n", styledDoc.getStyle("regular"));
			}
			// decide what style to use
			String style = "regular";
			if (msg.startsWith(">>"))
			{
				style = "alert";
			}
			else if (msg.startsWith(ownUsername))
			{
				style = "blue";
			}
			else if (msg.startsWith("#"))
			{
				style = "meta";
			}
			else if (msg.startsWith("*"))
			{
				style = "selfInfo";
			}
			styledDoc.insertString(styledDoc.getLength(), msg, styledDoc.getStyle(style));
		} catch (BadLocationException e)
		{
			AHLogger.error("ChatManager.displayMessage", "This shouldn't happen");
		}
		chatbox.setCaretPosition(chatbox.getDocument().getLength());
		chatbox.repaint();
	}

	/**
	 * Gets the chat box
	 * @return the chat box
	 */
	public JTextPane getChatBox()
	{
		return chatbox;
	}

	/**
	 * Gets the chat field
	 * @return the chat field
	 */
	public JTextField getChatField()
	{
		return chatField;
	}

	/**
	 * Grabs and clears the chat field text
	 * @return the chat field text
	 */
	public String clearChatFieldText()
	{
		String temp = chatField.getText();
		chatField.setText("");
		return temp;
	}

	/**
	 * Gets the chat field text
	 * @return the chat field text
	 */
	public String getChatFieldText()
	{
		return chatField.getText();
	}

	/**
	 * Sets the fixed size of the chat box
	 * @param width the width to set
	 * @param height the height to set
	 */
	public void setFixedSize(int width, int height)
	{
		int textFieldSize = 25;
		chatbox.setMinimumSize(new Dimension(width, height - textFieldSize));
		chatbox.setMaximumSize(new Dimension(width, Integer.MAX_VALUE));
		chatbox.setPreferredSize(new Dimension(width, height - textFieldSize));
		chatField.setMinimumSize(new Dimension(width, textFieldSize));
		chatField.setMaximumSize(new Dimension(width, textFieldSize));
		chatField.setPreferredSize(new Dimension(width, textFieldSize));
	}

}
